# CriteriaChain.java

    package org.codefilarete.stalactite.query.api;

    import org.codefilarete.stalactite.query.model.AbstractCriterion;
    import org.codefilarete.stalactite.query.model.ConditionalOperator;
    import org.codefilarete.stalactite.query.model.LogicalOperator;
    import org.codefilarete.stalactite.sql.ddl.structure.Column;

    import static org.codefilarete.stalactite.query.model.LogicalOperator.AND;
    import static org.codefilarete.stalactite.query.model.LogicalOperator.OR;

    /**
     * @author Guillaume Mary
     */
    public interface CriteriaChain<SELF extends CriteriaChain<SELF>> extends Iterable<AbstractCriterion> {

    	default SELF and(Column column, CharSequence condition) {
    		return add(AND, column, condition);
    	}

    	default SELF or(Column column, CharSequence condition) {
    		return add(OR, column, condition);
    	}

    	default SELF and(Column column, ConditionalOperator condition) {
    		return add(AND, column, condition);
    	}

    	default SELF or(Column column, ConditionalOperator condition) {
    		return add(OR, column, condition);
    	}

    	default SELF and(CriteriaChain<?> criteria) {
    		return add(AND, criteria);
    	}

    	default SELF or(CriteriaChain<?> criteria) {
    		return add(OR, criteria);
    	}

    	default SELF and(Object... columns) {
    		return add(AND, columns);
    	}

    	default SELF or(Object... columns) {
    		return add(OR, columns);
    	}

    	SELF add(LogicalOperator logicalOperator, Selectable<?> column, CharSequence condition);

    	SELF add(LogicalOperator logicalOperator, Selectable<?> column, ConditionalOperator<?, ?> condition);

    	SELF add(LogicalOperator logicalOperator, CriteriaChain<?> criteria);

    	SELF add(LogicalOperator logicalOperator, Object... columns);

    	SELF add(AbstractCriterion condition);

    	/**
    	 * Adds the given criteria to this chain by simply appending it to the end of the chain.
    	 * @param criteria the condition to be added to this chain
    	 * @return this
    	 */
    	SELF add(Iterable<AbstractCriterion> criteria);

    	default boolean isEmpty() {
    		return !iterator().hasNext();
    	}
    }